﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Eniux.Windows.ThreeDEngine.Helper;
using System.Windows.Media.Media3D;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Controls;

namespace Eniux.Windows.ThreeDEngine.Visual3Ds
{
    public abstract class Manipulator : UIElement3D
    {

        #region 变量
        /// <summary>
        ///  相机
        /// </summary>
        protected ProjectionCamera Camera;

        /// <summary>
        ///   碰撞面板法线
        /// </summary>
        protected Vector3D HitPlaneNormal;

        /// <summary>
        /// 父视窗
        /// </summary>
        protected Viewport3D ParentViewport;

        /// <summary>
        ///  几何模型
        /// </summary>
        protected GeometryModel3D model;

        #endregion

        #region 注册属性

        #region Color

        /// <summary>
        ///  颜色属性
        /// </summary>
        public static readonly DependencyProperty ColorProperty = DependencyProperty.Register(
            "Color", typeof(Color), typeof(Manipulator), new UIPropertyMetadata(ColorChanged));

        /// <summary>
        /// 获取或设置颜色
        /// </summary>
        public Color Color
        {
            get { return (Color)GetValue(ColorProperty); }
            set { SetValue(ColorProperty, value); }
        } 

        #endregion

        #region Offset

        /// <summary>
        ///  偏移属性
        /// </summary>
        public static readonly DependencyProperty OffsetProperty = DependencyProperty.Register(
            "Offset",
            typeof(Vector3D),
            typeof(Manipulator),
            new FrameworkPropertyMetadata(
                new Vector3D(0, 0, 0), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, PositionChanged));

        /// <summary>
        /// 获取或设置偏移
        /// </summary>
        public Vector3D Offset
        {
            get { return (Vector3D)GetValue(OffsetProperty); }
            set { SetValue(OffsetProperty, value); }
        } 
        #endregion

        #region Position

        /// <summary>
        ///  位置属性
        /// </summary>
        public static readonly DependencyProperty PositionProperty = DependencyProperty.Register(
            "Position",
            typeof(Point3D),
            typeof(Manipulator),
            new FrameworkPropertyMetadata(
                new Point3D(), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, PositionChanged));

        /// <summary>
        /// 获取或设置位置
        /// </summary>
        public Point3D Position
        {
            get { return (Point3D)GetValue(PositionProperty); }
            set { SetValue(PositionProperty, value); }
        } 

        #endregion

        #region TargetTransform

        /// <summary>
        ///  目标转换属性
        /// </summary>
        public static readonly DependencyProperty TargetTransformProperty =
            DependencyProperty.Register(
                "TargetTransform",
                typeof(Transform3D),
                typeof(Manipulator),
                new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

        /// <summary>
        /// 获取或设置目标转换
        /// </summary>
        public Transform3D TargetTransform
        {
            get { return (Transform3D)this.GetValue(TargetTransformProperty); }
            set { this.SetValue(TargetTransformProperty, value); }
        } 

        #endregion

        #region Value

        /// <summary>
        /// 值属性
        /// </summary>
        public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
            "Value",
            typeof(double),
            typeof(Manipulator),
            new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

        /// <summary>
        /// 获取或设置值
        /// </summary>
        public double Value
        {
            get { return (double)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        } 
        #endregion

        #endregion

        #region 构造、析构

        /// <summary>
        /// 默认构造函数
        /// </summary>
        public Manipulator()
        {
            this.model = new GeometryModel3D();
            this.Visual3DModel = this.model;
            this.OnGeometryChanged();
        }

        #endregion

        #region 方法

        protected static void GeometryChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((Manipulator)d).OnGeometryChanged();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="p"></param>
        /// <param name="hitPlaneOrigin"></param>
        /// <param name="hitPlaneNormal"></param>
        /// <returns></returns>
        protected virtual Point3D? GetHitPlanePoint(Point p, Point3D hitPlaneOrigin, Vector3D hitPlaneNormal)
        {
            return Viewport3DHelper.UnProject(this.ParentViewport, p, hitPlaneOrigin, hitPlaneNormal);
        }

        /// <summary>
        /// 几个模型改变
        /// </summary>
        protected abstract void OnGeometryChanged();

        /// <summary>
        ///重写MouseDown事件
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseDown(MouseButtonEventArgs e)
        {
            base.OnMouseDown(e);
            this.ParentViewport = Visual3DHelper.GetViewport3D(this);
            this.Camera = this.ParentViewport.Camera as ProjectionCamera;
            this.HitPlaneNormal = this.Camera.LookDirection;

            this.CaptureMouse();
        }

        /// <summary>
        /// 重写MouseUp事件
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseUp(MouseButtonEventArgs e)
        {
            base.OnMouseUp(e);
            this.ReleaseMouseCapture();
        }

        /// <summary>
        /// 将世界坐标转换为本地坐标
        /// </summary>
        /// <param name="worldPoint">世界坐标点</param>
        /// <returns></returns>
        protected Point3D ToLocal(Point3D worldPoint)
        {
            Matrix3D mat = Visual3DHelper.GetTransform(this);
            mat.Invert();
            var t = new MatrixTransform3D(mat);
            return t.Transform(worldPoint);
        }

        /// <summary>
        /// 将本地坐标转换为世界坐标
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        protected Point3D ToWorld(Point3D point)
        {
            Matrix3D mat = Visual3DHelper.GetTransform(this);
            var t = new MatrixTransform3D(mat);
            return t.Transform(point);
        }

        /// <summary>
        /// 将本地坐标转换为世界坐标
        /// </summary>
        /// <param name="vector"></param>
        /// <returns></returns>
        protected Vector3D ToWorld(Vector3D vector)
        {
            Matrix3D mat = Visual3DHelper.GetTransform(this);
            var t = new MatrixTransform3D(mat);
            return t.Transform(vector);
        }

        private static void ColorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((Manipulator)d).OnColorChanged();
        }

        private static void PositionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((Manipulator)d).OnPositionChanged();
        }

        private void OnColorChanged()
        {
            this.model.Material = MaterialHelper.CreateMaterial(this.Color);
            this.model.BackMaterial = this.model.Material;
        }

        private void OnPositionChanged()
        {
            this.Transform = new TranslateTransform3D(
                this.Position.X + this.Offset.X, this.Position.Y + this.Offset.Y, this.Position.Z + this.Offset.Z);
        }

        #endregion
    }
}
